package com.yixing.tech.entity.utils;

import com.yixing.tech.common.security.context.SessionUser;
import com.yixing.tech.common.security.context.UserContext;
import com.yixing.tech.entity.po.EntityData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.query.Criteria;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.function.Consumer;

/**
 * S5Utils
 *
 * @author yixing tech
 * @since 1.0.0
 */
@Slf4j
public abstract class EntityUtils {

    public static void fillUserInfo(EntityData entity) {
        SessionUser ucx = UserContext.getUser();
        entity.put("tenantId", ucx.getTenantId());
        entity.put("updateId", ucx.getId());
        entity.put("createId", ucx.getId());
    }

    public static Criteria newCriteria() {
        return Criteria.where("isDelete").ne(1);
    }


    public static <T> void canCastThen(Class<T> c, Object obj, Consumer<T> then) {
        if (obj != null && c.isInstance(obj)) {
            then.accept((T) obj);
        } else {
            if (obj != null) {
                log.error("canCastThen obj: {} class: {}", obj, c);
            }
        }
    }


    public static void canBeDouble(Object obj, Consumer<Double> then) {
        if (obj == null) {
            return;
        }
        if (obj instanceof Double) {
            then.accept((Double) obj);
        } else if (obj instanceof Integer) {
            then.accept(((Integer) obj).doubleValue());
        } else if (obj instanceof Long) {
            then.accept(((Long) obj).doubleValue());
        } else if (obj instanceof String) {
            then.accept(Double.parseDouble((String) obj));
        } else {
            try {
                then.accept(((Double) obj));
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

    public static Double safeGetDouble(Document doc, String attr) {
        return safeGetDouble(doc, attr, null);
    }

    public static Double safeGetDouble(Object obj, Double defaultValue) {
        if (obj == null) {
            return defaultValue;
        }
        if (obj instanceof Double) {
            return (Double) obj;
        } else if (obj instanceof Integer) {
            return ((Integer) obj).doubleValue();
        } else if (obj instanceof Long) {
            return ((Long) obj).doubleValue();
        } else if (obj instanceof String) {
            return Double.parseDouble((String) obj);
        } else {
            try {
                return (Double) obj;
            } catch (Throwable e) {
                return defaultValue;
            }
        }
    }

    public static List<ObjectId> safeGetObjectIdList(Document doc, String attr) {
        if(doc == null || StringUtils.isBlank(attr)) {
            return Collections.emptyList();
        }
        Object lObj = doc.get(attr);
        List<ObjectId> ids = new ArrayList<>();
        if (lObj instanceof Collection) {
            List<Object> lObjList = (List<Object>) lObj;
            for (Object x : lObjList) {
                if (x instanceof ObjectId) {
                    ids.add((ObjectId) x);
                } else if (x instanceof String) {
                    ids.add(new ObjectId(x + ""));
                }
            }
        }
        return ids;
    }

    public static Double safeGetDouble(Document doc, String attr, Double defaultValue) {
        if (doc == null) {
            return defaultValue;
        }
        Object obj = doc.get(attr);
        if(obj == null) {
            return defaultValue;
        }
        if (obj instanceof Double) {
            return (Double) obj;
        } else if (obj instanceof Integer) {
            return ((Integer) obj).doubleValue();
        } else if (obj instanceof Long) {
            return ((Long) obj).doubleValue();
        } else if (obj instanceof String) {
            return Double.parseDouble((String) obj);
        } else {
            try {
                return (Double) obj;
            } catch (Throwable e) {
                log.error("文档[{}] 属性[{}] 转不了Double", doc, attr);
                return defaultValue;
            }
        }
    }

    public static <T> List<T> safeGetList(Map doc, String attr, Class<T> clazz) {
        if (doc == null) {
            return Collections.emptyList();
        }
        Object obj = doc.get(attr);
        if (obj == null) {
            return Collections.emptyList();
        }
        if (obj instanceof List) {
            try {
                return (List<T>) obj;
            } catch (Throwable ignore) {
                log.error("safeGetList error, Doc: {}, attr: {}, class: {}", doc, attr, clazz, ignore);
                return Collections.emptyList();
            }
        } else {
            return Collections.emptyList();
        }
    }

    public static String formatRateStr(double source,  int decimalPlaces) {
        // 参数校验
        if (decimalPlaces < 0) {
            throw new IllegalArgumentException("小数位数不能为负数");
        }

        // 限制最大小数位数
        decimalPlaces = Math.min(decimalPlaces, 8);

        // 构建格式模板
        String pattern = "#";
        if (decimalPlaces > 0) {
            pattern += "." + repeatZeros(decimalPlaces);
        }
        DecimalFormat df = new DecimalFormat(pattern);
        df.setRoundingMode(RoundingMode.HALF_UP);
        return df.format(source);
    }

    private static String repeatZeros(int count) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append('#');
        }
        return sb.toString();
    }

}
